-module( kinematics_world ).

-export( [start/3] ).

-record( world, { bounds, tree, defaultCell, workers } ).



start( Bounds, CellSize, Overlap ) ->
  Overlap,
  io:format(
    "Starting world.\n"
    "Bounds:\n~p\n"
    "Cell size:\n~p\n", [ Bounds, CellSize ] ),
  CellF = fun( CellBounds, Aux ) ->
    Cell = { CellBounds, spawn_link( kinematics_cell, start, [ CellBounds ] ) },
    { Cell, Aux + 1 }
  end,
  { Tree, _ } = octree:build( Bounds, CellSize, CellF, 0 ),
  error_logger:info_msg( "Tree built: ~p\n", [ Tree ] ),
  DefaultCell = spawn_link( kinematics_cell, start, [ Bounds ] ),
  
  WorkerF = fun( _Idx ) -> spawn_link( kinematics_worker, start, [ Bounds, Tree, DefaultCell ] ) end,
  Workers = lists:map( WorkerF, lists:seq( 1, 10 ) ),
  
  loop( #world{ bounds=Bounds, tree=Tree, defaultCell=DefaultCell, workers=Workers } ).



loop( State ) ->
  receive
    destroy ->
      exit( terminate );
      
    { assign_worker, ObjPid } ->
      ObjPid ! { worker_assigned, selectWorker( State ) },
      loop( State );

    %%FIXME: Just redirect messages to some worker process
    { propagate_to_box, _Box, _M } = Msg ->
      W = selectWorker( State ),
      W ! Msg,
      loop( State );
      
    { propagate_to_all, _M } = Msg ->
      W = selectWorker( State ),
      W ! Msg,
      loop( State );

    %Debug
    M ->
      error_logger:error_msg( "Unknown msg ~p\n", [M] ),
      exit( unknown_msg )
  end.



selectWorker( State ) ->
  %Debug: just use first worker
  N = length( State#world.workers ),
  I = random:uniform( N ),
  lists:nth( I, State#world.workers ).
